/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.formserver.vmmanager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.formserver.viewmodel.collection.VMElementCollection;
import com.inspur.edp.formserver.viewmodel.collection.ViewObjectCollection;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelDeserializer;
import com.inspur.edp.formserver.viewmodel.json.model.ViewModelSerializer;
import com.inspur.edp.formserver.vmmanager.exception.VmManagerException;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;

public class TransferSerializer implements MetadataTransferSerializer {

    //region getMapper

    private ObjectMapper getMapper() {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(IGspCommonModel.class, new ViewModelDeserializer());
        module.addSerializer(IGspCommonModel.class, new ViewModelSerializer());
        mapper.registerModule(module);
        return mapper;
    }

    //endregion

    //region 序列化
    public final String serialize(IMetadataContent metadataContent) {
        GspViewModel viewModel = (GspViewModel) ((metadataContent instanceof GspViewModel)
            ? metadataContent : null);
        String modelJson;
        try {
            modelJson = getMapper().writeValueAsString(viewModel);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("ViewModel序列化失败！");
        }
        return modelJson;
    }

    private void dealContent(GspViewModel viewModel) {
        dealObject(viewModel.getMainObject());
    }

    private void dealObject(GspViewObject viewObject) {

        ViewObjectCollection childObjs = viewObject.getContainChildObjects();
        if (childObjs != null && childObjs.size() > 0) {
            childObjs.forEach((childObj) -> {
                dealObject((GspViewObject) childObj);
            });
        }

        VMElementCollection eles = viewObject.getContainElements();
        if (eles != null && eles.size() > 0) {
            eles.forEach(this::dealElement);
        }
    }

    private void dealElement(IGspCommonField element) {
        if (element.getObjectType() != GspElementObjectType.Association) {
            return;
        }

        GspAssociationCollection assos = element.getChildAssociations();
        if (assos != null && assos.size() > 0) {
            assos.forEach(this::dealAssociation);
        }
    }

    private void dealAssociation(GspAssociation association) {

        GspFieldCollection refEles = association.getRefElementCollection();
        if (refEles != null && refEles.size() > 0) {
            refEles.forEach((refEle) -> {
                dealRefElement(association, refEle);
            });
        }
    }

    private void dealRefElement(GspAssociation association, IGspCommonField refElement) {
        if (refElement.getObjectType() != GspElementObjectType.Association) {
            return;
        }
        RefCommonService service = SpringBeanUtils.getBean(RefCommonService.class);
        GspMetadata refMetadata = service.getRefMetadata(association.getRefModelID());
        if (refMetadata == null) {
            throw new VmManagerException("", "",
                "关联be[" + association.getRefModelID() + "] [" + association.getRefModelCode()
                    + "]没有获取到。",
                null, ExceptionLevel.Error, false);
        }
        GspBusinessEntity refBe = (GspBusinessEntity) refMetadata.getContent();
        IGspCommonObject refObj = refBe.findObjectById(association.getRefObjectID());
        if (refObj == null) {
            throw new VmManagerException("", "",
                "关联be[" + association.getRefModelCode() + "]中没有获取到节点[" + association.getRefObjectID()
                    + "] [" + association.getRefObjectCode() + "]。", null, ExceptionLevel.Error,
                false);
        }

        IGspCommonElement element = refObj.findElement(refElement.getRefElementId());
        if (element == null) {
            throw new VmManagerException("", "",
                "关联be[" + association.getRefModelCode() + "]中没有获取到字段[" + refElement.getRefElementId()
                    + "] [" + refElement.getLabelID() + "]。", null, ExceptionLevel.Error, false);
        }

        refElement.getChildAssociations().addAll(element.getChildAssociations().clone());

        dealElement(refElement);
    }
    //endregion

    public final IMetadataContent deserialize(String contentString) {
        try {
            return getMapper().readValue(contentString, GspViewModel.class);
        } catch (JsonProcessingException e) {
            throw new VmManagerException("", "", "vo反序列化失败" + contentString, null, ExceptionLevel.Error,
                false);

        }
    }
}
